package uy.org.softtech.cssuite.web.controladores;

import static org.springframework.util.Assert.notNull;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;

import javax.annotation.PostConstruct;

import net.minidev.json.JSONArray;

import org.apache.log4j.Logger;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.context.annotation.Configuration;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.IMap;

import uy.org.softtech.cssuite.core.Controlador;
import uy.org.softtech.cssuite.web.entidad.RespuestaJson;
import uy.org.softtech.cssuite.web.entidad.RespuestaReporte;

/**
 * Controlador encargado de atender las solicitudes relacionadas a los reportes a ser generados.
 * 
 * @author fabian.lobo
 */
@Configuration
@Controller("controlador-reportes")
@ManagedResource(
	objectName = "cssuite:type=Controlador,name=ControladorReportes", 
	description = "Controlador encargado de atender las solicitudes relacionadas a los reportes a ser generados.",
	log = true, logFile = "jmx.log", currencyTimeLimit = 15,
	persistPolicy = "OnUpdate", persistPeriod = 200
)
public class ControladorReportes extends Controlador {

	private Logger log = Logger.getLogger(getClass());
	
	private IMap reportes = Hazelcast.getMap("reportes");
	
	/**
	 * Método para verificar que todos los parámetros han sido seteados correctamente.
	 * 
	 * @author fabian.lobo
	 */
	@PostConstruct
	public void inicializacion(){
		super.inicializacion();
		
		notNull(reportes(), "La propiedad [reportes] de [" + getClass().getName() + "] no ha sido establecida.");
		
		log.info("Controlador encargado de atender las solicitudes relacionadas a los reportes a ser generados ha sido inicializado.");
	}
	
	/* 
	 * ---------------------------------------
	 * --------      REPORTES      -----------
	 * ---------------------------------------
	 */
	/**
	 * Genera un identificador para el almacenamiento temporal de los datos para generar el reporte solicitado
	 * 
	 * @author fabian.lobo
	 */
	@RequestMapping(method = RequestMethod.POST , value = "reporte.do", params = {"accion=REPORTAR", "modulo", "reporte", "headers", "datos"})
	@ResponseBody
	@Secured(value = {"ROLE_AUTENTICADO"})
	public RespuestaJson recibeSolicitudReporte(Locale locale, @RequestParam(value = "reporte") Reporte reporte, @RequestParam(value = "modulo") Modulo modulo, @RequestParam(value = "headers") String headers, @RequestParam(value = "datos") String datos) {
		ObjectMapper mapper = new ObjectMapper();
		String vista = reporte.toString() + "-" + modulo.toString();
		Map<String, Object> modelo = new HashMap<String, Object>();
		
		try {
			String titulo = null;
			switch(modulo) {
				case USUARIOS:
					titulo = fuenteMensajes().getMessage("etiqueta.gestionUsuarios", null, "Gestión de usuarios", locale);
					break;
				case SESIONES:
					titulo = fuenteMensajes().getMessage("etiqueta.gestionSesiones", null, "Gestión de sesiones", locale);
					break;
				case TAREAS:
					titulo = fuenteMensajes().getMessage("etiqueta.gestionTareas", null, "Gestión de tareas", locale);
					break;
				case CLIENTES:
					titulo = fuenteMensajes().getMessage("etiqueta.gestionClientes", null, "Gestión de clientes", locale);
					break;
			}
			modelo.put("REPORTE_TITULO", titulo);
			
			switch(reporte) {
			case XLS:
				modelo.put("REPORTE_NOMBRE_HOJA", titulo);
				break;
			case PDF:
				break;
			}
			
			JSONArray cabezales = mapper.readValue(headers, JSONArray.class);
			modelo.put("REPORTE_CABEZALES", cabezales);
			
			JSONArray celdas = mapper.readValue(datos, JSONArray.class);
			modelo.put("REPORTE_CELDAS", celdas);
			
			int filas = celdas.size();
			StringBuffer buffer = new StringBuffer();
			buffer.append(fuenteMensajes().getMessage("mensaje.listado.comienzo", null, "Se obtuvieron", locale))
				.append(" ")
				.append(filas)
				.append(" ")
				.append(fuenteMensajes().getMessage("mensaje.listado.fin", null, "registros.", locale));
			modelo.put("REPORTE_MENSAJE", buffer.toString());
			
		} catch (Exception e) {
			log.error(e);
		}
				
		RespuestaReporte respuesta = new RespuestaReporte(vista, modelo);
		String identificador = UUID.randomUUID().toString();
		reportes.put(identificador, respuesta);
		
		return new RespuestaJson(identificador);
	}
	
	/**
	 * Procesa la solicitud de un reporte.
	 * 
	 * @author fabian.lobo
	 */
	@RequestMapping(method = RequestMethod.GET, value = "reporte.do", params = {"accion=REPORTAR", "reporte"})
	@Secured(value = {"ROLE_AUTENTICADO"})
	public ModelAndView procesaSolicitudReporte(@RequestParam(value = "reporte") String reporte) {
		RespuestaReporte respuesta = (RespuestaReporte) reportes.get(reporte);
		if(respuesta != null) {
			reportes.remove(reporte);
			return new ModelAndView(respuesta.getVista(), respuesta.getModelo());
		} else {
			return new ModelAndView("redirect:inaccesible.do");
		}
	}
	
	/*
	 *  GETTERS
	 */	
	public IMap reportes() {
		return reportes;
	}
}
